package net.tv90.bfmccore;

import lk.vexview.api.VexViewAPI;
import lk.vexview.gui.components.VexImage;
import lk.vexview.hud.VexImageShow;
import lk.vexview.hud.VexTextShow;
import net.tv90.bfmccore.constant.RewardConstant;
import net.tv90.bfmccore.event.AttachmentUnlockEvent;
import net.tv90.bfmccore.event.ServiceStarGetEvent;
import net.tv90.bfmccore.event.UnlockEvent;
import net.tv90.bfmccore.game.GameBase;
import net.tv90.bfmccore.game.GameManager;
import net.tv90.bfmccore.helper.FactionHelper;
import net.tv90.bfmccore.helper.FlanHelper;
import net.tv90.bfmccore.helper.ItemHelper;
import net.tv90.bfmccore.util.KillLog;
import net.tv90.bfmccore.util.Ribbon;
import net.tv90.bfmccore.util.TempPermission;
import org.bitterorange.flansmodslain.FlansModAPI;
import org.bitterorange.flansmodslain.FlansModSlain;
import org.bitterorange.flansmodslain.actions.Action;
import org.bitterorange.flansmodslain.actions.Money;
import org.bitterorange.flansmodslain.actions.Point;
import org.bitterorange.flansmodslain.models.*;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;

import java.io.File;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static net.tv90.bfmccore.BFMCCore.PLUGIN_ROOT;
import static net.tv90.bfmccore.helper.FactionHelper.*;
import static net.tv90.bfmccore.helper.FlanHelper.WeaponTypeMap;
import static net.tv90.bfmccore.helper.FlanHelper.getWeaponType;
import static net.tv90.bfmccore.util.file.FileUtils.writeAllText;
import static net.tv90.bfmccore.util.file.FileUtils.writeAllTextAsAppendMode;
import static org.bitterorange.flansmodslain.FlansModSlain.getLinkedKillCountOf;

public class SlainListener implements Listener {

    /**
     * 储存玩家获得勋带的数量
     */
    public static HashMap<String, Integer> RibbonNumMap = loadRibbonData();
    /**
     * 储存勋带缓存数量
     */
    public static HashMap<String, Integer> RibbonCacheMap = new HashMap<>();
    public static ExecutorService killerInfo_pool = Executors.newFixedThreadPool(2);

    public static List<String> aiKillLog = new ArrayList<>();

    public static File generateKillFile(Player p) {
        return generateKillFile(p.getName());
    }

    public static File generateDeathFile(Player p) {
        if (!PLUGIN_ROOT.exists()) PLUGIN_ROOT.mkdir();
        File dataDirectory = new File(PLUGIN_ROOT, "data");
        if (!dataDirectory.exists()) dataDirectory.mkdir();
        return new File(dataDirectory, p.getName() + "_Death" + ".yml");
    }

    public static File generateKillFile(String playerName) {
        if (!PLUGIN_ROOT.exists()) PLUGIN_ROOT.mkdir();
        File dataDirectory = new File(PLUGIN_ROOT, "data");
        if (!dataDirectory.exists()) dataDirectory.mkdir();
        return new File(dataDirectory, playerName + "_Kill" + ".yml");
    }

    public static synchronized void saveAIKillLog() {
        File file = new File(PLUGIN_ROOT, "aiKillLog.csv");
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        List<String> aiKillLog = new ArrayList<>(SlainListener.aiKillLog);
        SlainListener.aiKillLog.clear();
        new Thread(() -> {
            try {
                for (String s : aiKillLog) {
                    writeAllTextAsAppendMode(file, s + "\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    @SuppressWarnings("unchecked")
    public static int getKillCount(Player killer, String weapon) {
        File file = generateKillFile(killer);
        try {
            HashMap<String, Integer> map = (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
            return map.getOrDefault(weapon, 0);
        } catch (Exception e) {
            return 0;
        }
    }

    @SuppressWarnings("unchecked")
    public static int getDeathCount(Player killed, String weapon) {
        File file = generateDeathFile(killed);
        try {
            HashMap<String, Integer> map = (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
            return map.getOrDefault(weapon, 0);
        } catch (Exception e) {
            return 0;
        }
    }

    @SuppressWarnings("unchecked")
    public static HashMap<String, Integer> getAllKillCount(Player killer) {
        File file = generateKillFile(killer);
        try {
            return (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    @SuppressWarnings("unchecked")
    public static HashMap<String, Integer> getAllKillCount(String killerName) {
        File file = generateKillFile(killerName);
        try {
            return (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    @SuppressWarnings("unchecked")
    public static HashMap<String, Integer> getAllDeathCount(Player killed) {
        File file = generateDeathFile(killed);
        try {
            return (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    /**
     * 加载所有玩家获得的勋带和数量
     *
     * @return Map K = 玩家_勋带_Ribbon  V = 数量
     */
    @SuppressWarnings("unchecked")
    public static HashMap<String, Integer> loadRibbonData() {
        if (!PLUGIN_ROOT.exists()) PLUGIN_ROOT.mkdir();
        File dataDirectory = new File(PLUGIN_ROOT, "ribbondata");
        if (!dataDirectory.exists()) dataDirectory.mkdir();
        File file = new File(dataDirectory, "ribbondata.yml");
        try {
            return (HashMap<String, Integer>) (new Yaml()).loadAs(Files.newInputStream(file.toPath()), HashMap.class);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    public static void showKillTitleHUD(Player p, String weapon, String killed, int dist) {
        int windowWidth = VexViewAPI.getPlayerClientWindowWidth(p);
        int windowHeight = VexViewAPI.getPlayerClientWindowHeight(p);

        double backgroundImageScale = 1.0 * windowWidth / 854;
        int backgroundImageX = (int) (100 * backgroundImageScale);
        int backgroundImageY = (int) (25 * backgroundImageScale);
        int backgroundImagePosX = -1;
        int backgroundImagePosY = 350 * windowHeight / 445;
        int lastTime = 3;

        double textScale = windowHeight / 445.0D;
        VexImage BNKIcon = new VexImage("[local]KillTitle/normalkill.png", backgroundImagePosX, backgroundImagePosY, backgroundImageX, backgroundImageY);
        VexTextShow nameText = new VexTextShow("TitleText1", 410 * windowWidth / 854, 352 * windowHeight / 445, 100, Collections.singletonList("§c" + killed), lastTime, 1.2 * textScale);
        VexTextShow weaponText = new VexTextShow("TitleText2", 410 * windowWidth / 854, 366 * windowHeight / 445, 100, Collections.singletonList(weapon), lastTime, 1.0 * textScale);
        VexTextShow distText = new VexTextShow("TitleText3", 410 * windowWidth / 854, 380 * windowHeight / 445, 100, Collections.singletonList("击杀距离 " + dist), lastTime, 1.0 * textScale);
        VexViewAPI.sendHUD(p, new VexImageShow("TitleIco1", BNKIcon, lastTime));
        VexViewAPI.sendHUD(p, nameText);
        VexViewAPI.sendHUD(p, weaponText);
        VexViewAPI.sendHUD(p, distText);
    }

    public static void addLine(Player p, String content, int lastTime){
        int windowWidth = VexViewAPI.getPlayerClientWindowWidth(p);
        int windowHeight = VexViewAPI.getPlayerClientWindowHeight(p);
        double textScale = windowHeight / 445.0D;
        VexTextShow t = new VexTextShow("TitleText3", 410 * windowWidth / 854, 380 * windowHeight / 445, 100, Collections.singletonList(content), lastTime, 1.0 * textScale);
        VexViewAPI.sendHUD(p, t);
    }

    /**
     * 显示击杀者信息
     *
     * @param killer    击杀者
     * @param killed    被击杀者
     * @param killType  击杀方式
     * @param weapon    武器
     * @param starCount 勤务之星数量
     */
    public void showKillerInfo(Player killer, Player killed, SlayType killType, String weapon, int starCount) {
        //获取击杀者信息
        String lifePercent = "§6" + (int) (killer.getHealth() * 5) + "%";
        String name = killer.getName();
        String faction = getFaction_Lang(killer);
        String distance = "§6" + (int) (killer.getLocation().distance(killed.getLocation())) + "m";
        String rank = "[" + FlansModSlain.rankOf(killer) + "] Rk." + FlansModSlain.rankIndexOf(killer);

        if (killType == SlayType.GUN) {
            try {
                ItemStack isk = killer.getInventory().getItemInHand();
                List<String> list = FlanHelper.getAllAttachment(isk);
                String list_scope = list.get(0);
                String list_barrel = list.get(1);
                String list_grip = list.get(2);
                String list_gadget = list.get(3);
                KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon, list_scope, list_barrel, list_grip, list_gadget);
                killInfoImage.starCount = starCount > 0 ? "  " + starCount + "★" : "";
                killInfoImage.showKillInfoHUD(killed);
            } catch (Exception e) {
                KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon);
                killInfoImage.starCount = starCount > 0 ? "  " + starCount + "★" : "";
                killInfoImage.showKillInfoHUD(killed);
            }
        } else if (killType == SlayType.VEHICLE) {
            List<String> weapons = FlansModAPI.getDisplayedVehicleWeapons(killer);
            String[] wps = new String[]{"", "", "", ""};
            for (int i = 0; i < weapons.size(); i++) {
                wps[i] = weapons.get(i);
            }
            KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon, wps[0], wps[1], wps[2], wps[3]);
            killInfoImage.starCount = starCount > 0 ? "  " + starCount + "★" : "";
            killInfoImage.showKillInfoHUD(killed);
        } else {
            KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon);
            killInfoImage.starCount = starCount > 0 ? "  " + starCount + "★" : "";
            killInfoImage.showKillInfoHUD(killed);
        }
    }

    public void showKillerInfo(EntitySoldierWrapper killer, Player killed, SlayType killType, String weapon) {
        //获取击杀者信息
        String lifePercent = "§6" + (killer.getHealth() * 5) + "%";
        String name = killer.getName();
        String faction = getFaction_Lang(killer);
        String distance = "§6" + (int) (killer.getLocation().distance(killed.getLocation())) + "m";
        String rank = "";

        if (killType == SlayType.GUN) {
            try {
                String list_scope = FlansModAPI.nameOfWeapon(ItemHelper.idToItem(killer.getGunScope())).replace("AIR", "金属瞄具");
                String list_barrel = FlansModAPI.nameOfWeapon(ItemHelper.idToItem(killer.getGunBarrel())).replace("AIR", "原厂枪管");
                String list_grip = FlansModAPI.nameOfWeapon(ItemHelper.idToItem(killer.getGunGrip())).replace("AIR", "无下挂");
                String list_gadget = FlansModAPI.nameOfWeapon(ItemHelper.idToItem(killer.getGunGadget())).replace("AIR", "无附挂");
                KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon, list_scope, list_barrel, list_grip, list_gadget);
                killInfoImage.starCount = "";
                killInfoImage.showKillInfoHUD(killed);
            } catch (Exception e) {
                KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon);
                killInfoImage.starCount = "";
                killInfoImage.showKillInfoHUD(killed);
            }
        } else {
            KillInfoImage killInfoImage = new KillInfoImage(name, lifePercent, distance, rank, faction, weapon);
            killInfoImage.starCount = "";
            killInfoImage.showKillInfoHUD(killed);
        }
    }

    @EventHandler
    public void onAiDeath(SoldierDeathEvent event) {
        if(event.isSuicide() && event.getSoldier() != null) {
            EntitySoldierWrapper soldier = event.getSoldier();
            String name = soldier.getName();
            getTeamer(soldier).forEach(p -> p.sendMessage("§l§a " + name + " §f[SUICIDE] §a" + name));
            getEnemies(soldier).forEach(p -> p.sendMessage("§l§c " + name + " §f[SUICIDE] §c" + name));
        }
    }

    @EventHandler
    public void playerDeath(PlayerCommandPreprocessEvent e) {
        Player player = e.getPlayer();
        String name = player.getName();
        if (e.getMessage().equals("/suicide")) {
            getTeamer(player).forEach(p -> p.sendMessage("§l§a " + name + " §f[SUICIDE] §a" + name));
            getEnemies(player).forEach(p -> p.sendMessage("§l§c " + name + " §f[SUICIDE] §c" + name));
        }
    }

    @EventHandler
    public void playerSlainStatistics(PlayerSlainEvent e) throws Exception {

        SlayType killType = e.getType();
        String weapon;
        if (e.isVehicleKill()) {
            weapon = FlansModAPI.getPlayerVehicle(e.getPlayerKiller());
        } else {
            weapon = FlansModAPI.nameOfWeapon(e.getOriginalMaterial());
        }

        if (weapon == null) throw new RuntimeException("weapon is null!");
        String weaponType = getWeaponType(weapon);

        //AI击杀玩家
        if (e.isKillerAI() && !e.isKilledAI()) {
            EntitySoldierWrapper killer = e.getKillerAI();
            Player killed = e.getPlayerKilled();
            double distance = killer.getLocation().distance(killed.getLocation());
            getTeamer(killer).forEach(p -> p.sendMessage("§l§a " + killer.getName() + " §f[" + weapon + "] §c" + killed.getName()));
            getTeamer(killed).forEach(p -> p.sendMessage("§l§c " + killer.getName() + " §f[" + weapon + "] §a" + killed.getName()));
            showKillerInfo(killer, killed, killType, weapon);

            KillLog log = KillLog.builder()
                    .country(killer.getCountry())
                    .weapon(weapon)
                    .world(killer.getLocation().getWorld().getName())
                    .killerX(killer.getLocation().getX())
                    .killerY(killer.getLocation().getY())
                    .killerZ(killer.getLocation().getZ())
                    .killedX(killed.getLocation().getX())
                    .killedY(killed.getLocation().getY())
                    .killedZ(killed.getLocation().getZ())
                    .killerHealth(killer.getHealth())
                    .time(LocalDateTime.now())
                    .killerName(killer.getName())
                    .killedName(killed.getName())
                    .isHeadshot(e.isHeadShot())
                    .distance(distance)
                    .build();
            aiKillLog.add(log.toCsv());

            FlansModAPI.spawnCorpse(killed.getWorld(), killed.getLocation().getX(), killed.getLocation().getY() - 1, killed.getLocation().getZ(), killed);
        }

        //AI击杀AI
        else if (e.isKillerAI() && e.isKilledAI()) {
            EntitySoldierWrapper killer = e.getKillerAI();
            EntitySoldierWrapper killed = e.getKilledAI();
            double distance = killer.getLocation().distance(killed.getLocation());
            getTeamer(killer).forEach(p -> p.sendMessage("§l§a " + killer.getName() + " §f[" + weapon + "] §c" + killed.getName()));
            getTeamer(killed).forEach(p -> p.sendMessage("§l§c " + killer.getName() + " §f[" + weapon + "] §a" + killed.getName()));

            KillLog log = KillLog.builder()
                    .country(killer.getCountry())
                    .weapon(weapon)
                    .world(killer.getLocation().getWorld().getName())
                    .killerX(killer.getLocation().getX())
                    .killerY(killer.getLocation().getY())
                    .killerZ(killer.getLocation().getZ())
                    .killedX(killed.getLocation().getX())
                    .killedY(killed.getLocation().getY())
                    .killedZ(killed.getLocation().getZ())
                    .killerHealth(killer.getHealth())
                    .time(LocalDateTime.now())
                    .killerName(killer.getName())
                    .killedName(killed.getName())
                    .isHeadshot(e.isHeadShot())
                    .distance(distance)
                    .build();
            aiKillLog.add(log.toCsv());
        }

        //玩家击杀AI
        else if (!e.isKillerAI() && e.isKilledAI()) {
            Player killer = e.getPlayerKiller();
            EntitySoldierWrapper killed = e.getKilledAI();
            double distance = killer.getLocation().distance(killed.getLocation());

            getTeamer(killer).forEach(p -> p.sendMessage("§l§a " + killer.getName() + " §f[" + weapon + "] §c" + killed.getName()));
            getTeamer(killed).forEach(p -> p.sendMessage("§l§c " + killer.getName() + " §f[" + weapon + "] §a" + killed.getName()));

            HashMap<String, Integer> killMap = getAllKillCount(killer);
            int killCount = killMap.getOrDefault(weapon, 0);
            killCount++;
            double totalMoneyAdded = 2.0D;
            int totalPointsAdded = 1;
            //连续击杀
            FlansModSlain.addLinkedKill(killer);
            int linkedKillCount = FlansModSlain.getLinkedKillCountOf(killer);

            //击杀AI固定2游戏币1军衔
            Money.give(killer, totalMoneyAdded);
            Point.add(killer, totalPointsAdded);
            killer.sendMessage("§e[确认击杀]你获得" + (int) totalMoneyAdded + "游戏币和" + totalPointsAdded + "军衔");

            if (linkedKillCount > 2) {
                killer.sendMessage("§e[连续击杀] Combo " + linkedKillCount);
            }

            //储存破片手榴弹的击杀数量
            if (weapon.equals("RGD-5 Frag") || weapon.equals("M67 Frag") || weapon.equals("TYPE-82 Frag")) {
                int grenadeKill = killMap.getOrDefault("Grenade", 0);
                grenadeKill++;
                killMap.put("Grenade", grenadeKill);
            }

            //储存某种类武器的击杀数量
            int typeKillCount = killMap.getOrDefault(getCountry2(killer) + weaponType, 0);
            typeKillCount++;
            killMap.put(getCountry2(killer) + weaponType, typeKillCount);

            //储存该武器的击杀数量
            killMap.put(weapon, killCount);
            saveKillFile(killMap, killer);

            System.out.println(killer.getName() + "用" + weapon + "[种类" + weaponType + "]击杀了" + killed.getName() + "，击杀方式为" + killType);

            Bukkit.getServer().getPluginManager().callEvent(new UnlockEvent(weapon, killCount, killer, killMap));
            Bukkit.getServer().getPluginManager().callEvent(new AttachmentUnlockEvent(getCountry2(killer) + weaponType, typeKillCount, killer, killMap));

            //勤务之星
            if (killCount % 100 == 0) {
                Bukkit.getServer().getPluginManager().callEvent(new ServiceStarGetEvent(killer, weapon, killCount / 100));
            }

            //显示击杀者信息
            showKillTitleHUD(killer, weapon, killed.getName(), (int) distance);
            killer.playSound(killer.getLocation(), "custom.BF1Kill", 100.0f, 1.0f);

            //VIP战斗增益
            if (killer.hasPermission("bfmc.vip2")) {
                Point.add(killer, 1);
                Money.give(killer, 1);
                killer.sendMessage("§e[VIP战斗增益]你额外获得1军衔和1游戏币");
            }

            //每用指定种类的武器完成10次击杀，获得战斗勋带
            if (!Objects.equals(weaponType, "Unclassified")) {
                Ribbon.addNumberForRibbon(killer, weaponType, WeaponTypeMap.get(weaponType), 10);
            }

            //神射手勋带
            if (distance >= 150 && killType != SlayType.VEHICLE) {
                Ribbon.addNumberForRibbon(killer, "Farshoot", "神射手", 10);
            }

            FlansModSlain.saveData();

            KillLog log = KillLog.builder()
                    .country(FactionHelper.getCountry2(killer))
                    .weapon(weapon)
                    .world(killer.getLocation().getWorld().getName())
                    .killerX(killer.getLocation().getX())
                    .killerY(killer.getLocation().getY())
                    .killerZ(killer.getLocation().getZ())
                    .killedX(killed.getLocation().getX())
                    .killedY(killed.getLocation().getY())
                    .killedZ(killed.getLocation().getZ())
                    .killerHealth(killer.getHealth())
                    .time(LocalDateTime.now())
                    .killerName(killer.getName())
                    .killedName(killed.getName())
                    .isHeadshot(e.isHeadShot())
                    .distance(distance)
                    .build();
            aiKillLog.add(log.toCsv());
        }

        //玩家击杀玩家
        else if (!e.isKilledAI() && !e.isKillerAI()) {
            Player killer = e.getPlayerKiller(), killed = e.getPlayerKilled();
            double distance = killer.getLocation().distance(killed.getLocation());
            KillLog log = KillLog.builder()
                    .country(FactionHelper.getCountry2(killer))
                    .weapon(weapon)
                    .world(killer.getLocation().getWorld().getName())
                    .killerX(killer.getLocation().getX())
                    .killerY(killer.getLocation().getY())
                    .killerZ(killer.getLocation().getZ())
                    .killedX(killed.getLocation().getX())
                    .killedY(killed.getLocation().getY())
                    .killedZ(killed.getLocation().getZ())
                    .killerHealth(killer.getHealth())
                    .time(LocalDateTime.now())
                    .killerName(killer.getName())
                    .killedName(killed.getName())
                    .isHeadshot(e.isHeadShot())
                    .distance((int) distance)
                    .build();
            aiKillLog.add(log.toCsv());

            getTeamer(killer).forEach(p -> p.sendMessage("§l§a " + killer.getName() + " §f[" + weapon + "] §c" + killed.getName()));
            getTeamer(killed).forEach(p -> p.sendMessage("§l§c " + killer.getName() + " §f[" + weapon + "] §a" + killed.getName()));

            //获得并更新击杀数据
            HashMap<String, Integer> killMap = getAllKillCount(killer);
//        HashMap<String, Integer> deathMap = getAllDeathCount(killed);
            int killCount = killMap.getOrDefault(weapon, 0);
//        int deathCount =  deathMap.getOrDefault(weapon, 0);
            killCount++;
//        deathCount++;

            //计算游戏币和军衔
            double totalMoneyAdded = 0.0D;
            int totalPointsAdded = 0;
            double moneyForNormalKill = 8.0D;

            totalMoneyAdded += moneyForNormalKill;

            //连续击杀
            FlansModSlain.addLinkedKill(killer);
            int linkedKillCount = FlansModSlain.getLinkedKillCountOf(killer);
            List<Action> linkedKillActions = FlansModSlain.linkedKillActionsOfCount(linkedKillCount);
            for (Action action : linkedKillActions) {
                Action.Response actionResponse = action.doActionTo(killer);
                totalMoneyAdded += actionResponse.getMoneyAdded();
                totalPointsAdded += actionResponse.getPointsAdded();
            }
            List<Action> distantKillActions = FlansModSlain.actionsAtDistance(distance);
            if (!distantKillActions.isEmpty()) {
                for (Action action : distantKillActions) {
                    Action.Response actionResponse = action.doActionTo(killer);
                    totalMoneyAdded += actionResponse.getMoneyAdded();
                    totalPointsAdded += actionResponse.getPointsAdded();
                }
            }
            if (linkedKillCount > 2) {
                killer.sendMessage("§e[连续击杀] Combo " + linkedKillCount);
            }

            Money.give(killer, totalMoneyAdded * RewardConstant.MONEY_MAGNIFICATION);
            Point.add(killer, totalPointsAdded * RewardConstant.RANK_MAGNIFICATION);
            killer.sendMessage("§e[确认击杀]你获得" + totalMoneyAdded * RewardConstant.MONEY_MAGNIFICATION + "游戏币和" + totalPointsAdded * RewardConstant.RANK_MAGNIFICATION + "军衔");

            //储存破片手榴弹的击杀数量
            if (weapon.equals("RGD-5 Frag") || weapon.equals("M67 Frag") || weapon.equals("TYPE-82 Frag")) {
                int grenadeKill = killMap.getOrDefault("Grenade", 0);
                grenadeKill++;
                killMap.put("Grenade", grenadeKill);
            }

            //储存某种类武器的击杀数量
            int typeKillCount = killMap.getOrDefault(getCountry2(killer) + weaponType, 0);
            typeKillCount++;
            killMap.put(getCountry2(killer) + weaponType, typeKillCount);

            //储存该武器的击杀数量
            killMap.put(weapon, killCount);
            saveKillFile(killMap, killer);
//        deathMap.put(weapon, deathCount);
//        saveDeathFile(deathMap, killed);

            System.out.println(killer.getName() + "用" + weapon + "[种类" + weaponType + "]击杀了" + killed.getName() + "，击杀方式为" + killType);
            //System.out.println("Ori=" + e.getOriginalMaterial() + " typeCount= " + typeKillCount + " Count= " + killCount + " isHeadShot=" + e.isHeadShot());

            Bukkit.getServer().getPluginManager().callEvent(new UnlockEvent(weapon, killCount, killer, killMap));
            Bukkit.getServer().getPluginManager().callEvent(new AttachmentUnlockEvent(getCountry2(killer) + weaponType, typeKillCount, killer, killMap));

            //勤务之星
            if (killCount % 100 == 0) {
                Bukkit.getServer().getPluginManager().callEvent(new ServiceStarGetEvent(killer, weapon, killCount / 100));
            }

            //显示击杀者信息
            showKillerInfo(killer, killed, killType, weapon, killCount / 100);
            showKillTitleHUD(killer, weapon, killed.getName(), (int) distance);
            killer.playSound(killer.getLocation(), "custom.BF1Kill", 100.0f, 1.0f);

            //击杀小队长奖励
            if (TempPermission.hasTempPerm(killed, "bfmc.squadleader")) {
                killer.sendMessage("§e[小队歼灭]你击杀了小队长" + killed.getName());
            }

            //VIP战斗增益
            if (killer.hasPermission("bfmc.vip2") && !killed.hasPermission("bfmc.vip2")) {
                Point.add(killer, 2);
                Money.give(killer, 5);
                killer.sendMessage("§e[VIP战斗增益]你额外获得2军衔和5游戏币");
            }

//        if (killed.hasPermission("bfmc.vip2")) {
//            Point.add(killer, 2);
//            Money.give(killer, 2);
//            killer.sendMessage("§e[战斗增益]你击杀了VIP用户，额外获得2军衔和2游戏币");
//        }

            //每用指定种类的武器完成10次击杀，获得战斗勋带
            if (!Objects.equals(weaponType, "Unclassified")) {
                Ribbon.addNumberForRibbon(killer, weaponType, WeaponTypeMap.get(weaponType), 10);
            }

            //神射手勋带
            if (distance >= 150 && killType != SlayType.VEHICLE) {
                Ribbon.addNumberForRibbon(killer, "Farshoot", "神射手", 10);
            }

            //小队毁灭勋带
            if (TempPermission.hasTempPerm(killed, "bfmc.squadleader")) {
                Ribbon.addNumberForRibbon(killer, "SquadWipe", "小队歼灭", 10);
            }

            //阻止连续击杀
            int enemyLinkedKillCount = getLinkedKillCountOf(killed);
            if (enemyLinkedKillCount >= 3) {
                Money.give(killer, enemyLinkedKillCount);
                killer.sendMessage("§e[阻止连杀]你用" + weapon + "阻止了" + killed.getName() + "的" + enemyLinkedKillCount + "次连续击杀,获得" + enemyLinkedKillCount + "游戏币");
                //阻止连杀勋带
                Ribbon.addNumberForRibbon(killer, "PreventLinkedKill", "连杀终结", 10);
            }

            //爆头
            if (e.isHeadShot()) {
                Ribbon.addNumberForRibbon(killer, "Headshot", "爆头", 10);
            }

            FlansModAPI.spawnCorpse(killed.getWorld(), killed.getLocation().getX(), killed.getLocation().getY() - 1, killed.getLocation().getZ(), killed);
        }
    }

    public void saveKillFile(HashMap<String, Integer> map, Player p) throws Exception {
        writeAllText(generateKillFile(p), (new Yaml()).dumpAs(map, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public void saveDeathFile(HashMap<String, Integer> map, Player p) throws Exception {
        writeAllText(generateDeathFile(p), (new Yaml()).dumpAs(map, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    /**
     * 玩家被击杀后显示的击杀者信息
     */
    public static class KillInfoImage {
        public double backgroundImageScale = 0.8;
        public int backgroundImageX = (int) (800 * backgroundImageScale);
        public int backgroundImageY = (int) (150 * backgroundImageScale);
        public int backgroundImagePosX = -1;
        public int backgroundImagePosY = 250;
        public int lastTime = 4;
        public String killerName = "TV90";
        public String killerLifePercent = "100%";
        public String killDistance = "114m";
        public String killerRank = "[一级准尉III]";
        public String killerFaction = "美国突击兵";
        public String killerGun = "AK74M";
        public String killerGun_att1 = "";
        public String killerGun_att2 = "";
        public String killerGun_att3 = "";
        public String killerGun_att4 = "";
        public String starCount = "";
        public double attachmentIconScale;
        public int attachmentIconX;
        public int attachmentIconY;
        public int customizeIconX;
        public int customizeIconY;
        public int weaponIconX;
        public int weaponIconY;

        public KillInfoImage() {
        }

        public KillInfoImage(String killerName, String killerLifePercent, String killDistance, String killerRank, String killerFaction, String killerGun, String killerGun_att1, String killerGun_att2, String killerGun_att3, String killerGun_att4) {
            this.killerName = killerName;
            this.killerLifePercent = killerLifePercent;
            this.killDistance = killDistance;
            this.killerRank = killerRank;
            this.killerFaction = killerFaction;
            this.killerGun = killerGun;
            this.killerGun_att1 = killerGun_att1;
            this.killerGun_att2 = killerGun_att2;
            this.killerGun_att3 = killerGun_att3;
            this.killerGun_att4 = killerGun_att4;
        }

        public KillInfoImage(String killerName, String killerLifePercent, String killDistance, String killerRank, String killerFaction, String killerGun) {
            this.killerName = killerName;
            this.killerLifePercent = killerLifePercent;
            this.killDistance = killDistance;
            this.killerRank = killerRank;
            this.killerFaction = killerFaction;
            this.killerGun = killerGun;
        }

        public void showKillInfoHUD(Player p) {
            int windowWidth = VexViewAPI.getPlayerClientWindowWidth(p);
            int windowHeight = VexViewAPI.getPlayerClientWindowHeight(p);
            //System.out.println(windowWidth + "*" + windowHeight);

            backgroundImageScale = 0.8 * windowWidth / 854;
            backgroundImageX = (int) (800 * backgroundImageScale);
            backgroundImageY = (int) (150 * backgroundImageScale);
            backgroundImagePosX = -1;
            backgroundImagePosY = 250 * windowHeight / 445;

            double textScale = 0.8 * windowHeight / 445;

            attachmentIconScale = 1.0 * windowWidth / 854;
            attachmentIconX = (int) (32 * attachmentIconScale);
            attachmentIconY = (int) (32 * attachmentIconScale);

            customizeIconX = (int) (90 * attachmentIconScale);
            customizeIconY = (int) (90 * attachmentIconScale);

            weaponIconX = (int) (80 * attachmentIconScale);
            weaponIconY = (int) (80 * attachmentIconScale);

            VexImage backgroundImage = new VexImage("[local]KillInfo/killInfoBNK.png", backgroundImagePosX, backgroundImagePosY, backgroundImageX, backgroundImageY);
            VexViewAPI.sendHUD(p, new VexImageShow("backgroundImage", backgroundImage, lastTime));

            VexImage attachmentScopeIcon = new VexImage("[local]KillInfo/attachment/" + killerGun_att1 + ".png", 600 * windowWidth / 854, 270 * windowHeight / 445, attachmentIconX, attachmentIconY);
            VexImage attachmentBarrelIcon = new VexImage("[local]KillInfo/attachment/" + killerGun_att2 + ".png", 600 * windowWidth / 854, 295 * windowHeight / 445, attachmentIconX, attachmentIconY);
            VexImage attachmentGripIcon = new VexImage("[local]KillInfo/attachment/" + killerGun_att3 + ".png", 600 * windowWidth / 854, 320 * windowHeight / 445, attachmentIconX, attachmentIconY);
            VexImage attachmentGadgetIcon = new VexImage("[local]KillInfo/attachment/" + killerGun_att4 + ".png", 600 * windowWidth / 854, 345 * windowHeight / 445, attachmentIconX, attachmentIconY);
            VexImage customizeIcon = new VexImage("[local]KillInfo/customize/" + killerName + ".png", 297 * windowWidth / 854, 276 * windowHeight / 445, customizeIconX, customizeIconY);
            VexImage weaponIcon = new VexImage("[local]KillInfo/weapon/" + killerGun + ".png", 470 * windowWidth / 854, 276 * windowHeight / 445, weaponIconX, weaponIconY);

            VexViewAPI.sendHUD(p, new VexImageShow("Icon1", attachmentScopeIcon, lastTime));
            VexViewAPI.sendHUD(p, new VexImageShow("Icon2", attachmentBarrelIcon, lastTime));
            VexViewAPI.sendHUD(p, new VexImageShow("Icon3", attachmentGripIcon, lastTime));
            VexViewAPI.sendHUD(p, new VexImageShow("Icon4", attachmentGadgetIcon, lastTime));
            VexViewAPI.sendHUD(p, new VexImageShow("Icon5", customizeIcon, lastTime));
            VexViewAPI.sendHUD(p, new VexImageShow("Icon6", weaponIcon, lastTime));

            VexTextShow killerNameText = new VexTextShow("Text1", 114 * windowWidth / 854, 253 * windowHeight / 445, 100, Collections.singletonList("§6" + killerName), lastTime, 3.5 * textScale);
            VexTextShow killerLifePercentText = new VexTextShow("Text2", 125 * windowWidth / 854, 310 * windowHeight / 445, 100, Collections.singletonList(killerLifePercent), lastTime, 3.5 * textScale);
            VexTextShow killDistanceText = new VexTextShow("Text3", 205 * windowWidth / 854, 310 * windowHeight / 445, 100, Collections.singletonList(killDistance), lastTime, 3.5 * textScale);
            VexTextShow killerRankText = new VexTextShow("Text4", 125 * windowWidth / 854, 350 * windowHeight / 445, 100, Collections.singletonList(killerRank), lastTime, 2.5 * textScale);
            VexTextShow killerFactionText = new VexTextShow("Text5", 435 * windowWidth / 854, 255 * windowHeight / 445, 100, Collections.singletonList(killerFaction), lastTime, 2.0 * textScale);
            VexTextShow killerGunText = new VexTextShow("Text6", 435 * windowWidth / 854, 355 * windowHeight / 445, 100, Collections.singletonList(killerGun + starCount), lastTime, 2.5 * textScale);
            VexTextShow killerGun_ScopeText = new VexTextShow("Text7", 630 * windowWidth / 854, 280 * windowHeight / 445, 100, Collections.singletonList(killerGun_att1), lastTime, 2.0 * textScale);
            VexTextShow killerGun_BarrelText = new VexTextShow("Text8", 630 * windowWidth / 854, 305 * windowHeight / 445, 100, Collections.singletonList(killerGun_att2), lastTime, 2.0 * textScale);
            VexTextShow killerGun_GripText = new VexTextShow("Text9", 630 * windowWidth / 854, 330 * windowHeight / 445, 100, Collections.singletonList(killerGun_att3), lastTime, 2.0 * textScale);
            VexTextShow killerGun_GadgetText = new VexTextShow("TextA", 630 * windowWidth / 854, 355 * windowHeight / 445, 100, Collections.singletonList(killerGun_att4), lastTime, 2.0 * textScale);
            VexViewAPI.sendHUD(p, killerNameText);
            VexViewAPI.sendHUD(p, killerLifePercentText);
            VexViewAPI.sendHUD(p, killDistanceText);
            VexViewAPI.sendHUD(p, killerNameText);
            VexViewAPI.sendHUD(p, killerRankText);
            VexViewAPI.sendHUD(p, killerFactionText);
            VexViewAPI.sendHUD(p, killerGunText);
            VexViewAPI.sendHUD(p, killerGun_ScopeText);
            VexViewAPI.sendHUD(p, killerGun_BarrelText);
            VexViewAPI.sendHUD(p, killerGun_GripText);
            VexViewAPI.sendHUD(p, killerGun_GadgetText);
        }
    }

}
